-module(opt_complex).
-export([minn_sx_complex/2, maxn_sx_complex/2,  branching_process/4, test/0]).
-import(opt).
-import(make_fun).


left_half( L ) ->
    lists:sublist(L, erlang:trunc(length(L)/2) ).

right_half( L ) ->
    lists:nthtail(erlang:trunc(length(L)/2), L). 

branching_process(F, Sxc, BPID, Tag) ->
    LSxc = length(Sxc),
    Send_best_of = fun (X, Y) ->
        if 
            X == [] ->
                BPID ! {Tag, Y};
            Y == [] ->
                BPID ! {Tag, X};
            true ->
                case apply(F, X) < apply(F, Y) of
                    true ->
                        BPID ! {Tag, X};
                    false ->
                        BPID ! {Tag, Y}
                end
        end
    end,
    if 
        LSxc == 1 ->
            {confirmed, X} = opt:minn_sx(F, hd(Sxc)),
            BPID ! {Tag, X};
        LSxc > 1 ->
            spawn( opt_complex, branching_process, [F, left_half(Sxc), self(), left] ),
            spawn( opt_complex, branching_process, [F, right_half(Sxc), self(), right] ),
            receive 
                {left, X} ->
                    receive 
                        {right, Y} ->
                            Send_best_of(X, Y)
                    end;
                {right, X} ->
                    receive 
                        {left, Y} ->
                            Send_best_of(X, Y)
                    end
            end
    end.

% in: F - target function, Sxc - simplex complex given by list of simplexes (given by their vertexes lists)
% out: {confirmed, [X1, X2, ...]} if local minimum found in iterations set in 'opt.erl', {confirmed, []} if not
minn_sx_complex(F, Sxc) ->
    spawn(opt_complex, branching_process, [F, Sxc, self(), main]),
    receive 
        {main, X} ->
            {confirmed, X}  % 'confirmed' is here for homogenity reasons only
    end.

% the same is in 'minn_sx_complex'
maxn_sx_complex(F, Sxc) ->
    minn_sx_complex(make_fun:inverse(F), Sxc).


%%%%%% testing part
sxc() ->
    [[[1,1], [4,0], [0,4]], [[1,1], [4,0], [2,-4]], [[4,0], [0,4]], [[1,1], [4,0]], [[1,1]], [[4,0]]].

t_f2( X, Y ) ->
    - (X-4)*(X-4) - (Y-3)*(Y-3).

test() ->
    erlang:display(maxn_sx_complex(fun t_f2/2, sxc())).
